<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:xf="http://www.w3.org/2002/xforms"
	xmlns:ccts="urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2"
	xmlns:ram="urn:un:unece:uncefact:data:draft:ReusableAggregateBusinessInformationEntity:1"
	exclude-result-prefixes="xsd xsl">
	
	<xsl:import href="GlobalVars.xsl"/>
	<xsl:import href="GlobalTemplates.xsl"/>
	<xsl:import href="Typelist.xsl" />
	
	<xsl:import href="AmountType.xsl"/>
	<xsl:import href="BinaryObjectType.xsl"/>
	<xsl:import href="DateTimeType.xsl"/>
	<xsl:import href="IDType.xsl"/>
	<xsl:import href="CodeType.xsl"/>
	<xsl:import href="MeasureType.xsl"/>
	<xsl:import href="NameType.xsl"/>
	<xsl:import href="QuantityType.xsl"/>
	<xsl:import href="TextType.xsl"/>
	<xsl:import href="IndicatorType.xsl"/>
	
	<!-- 
		This template creates the message instance and the instances that are representing codelists.
		@param rootElement - The root element of the message instance.
		@param prefix - The namespaceprefix for the rootelement.
	-->
	<xsl:template name="GenerateInstances">
		<xsl:param name="element.root" />
		<xsl:param name="element.root.prefix" />
		
		<xsl:variable name="message.document" select="concat( $element.root, '.xml' )" />
		
		<!--
			This part creates a message instance in a seperate document.
		-->
		<xsl:result-document href="{$message.document}">
			<xsl:element name="{$element.root}" namespace="{$global.ns.target}">
				<xsl:copy-of select="namespace::ram" />
				<xsl:attribute name="xsi:schemaLocation"><xsl:value-of 
					select="$global.ns.target"/><xsl:value-of select="concat( ' ', document-uri(/) )"/></xsl:attribute>
				<xsl:call-template name="BuildMessageInstance">
					<xsl:with-param name="element.type" select="@type" />
					<xsl:with-param name="element.prefix" select="$element.root.prefix" />
				</xsl:call-template>
			</xsl:element>
		</xsl:result-document>
		
		<!-- 
			This part creates a reference to the document which contains the message instance in the 
			html document.		
		-->
		<xsl:element name="xf:instance">
			<xsl:attribute name="id"><xsl:value-of select="$global.instance.message"/></xsl:attribute>
			<xsl:attribute name="src" select="$message.document" />
		</xsl:element>
		
		<xsl:call-template name="BuildCodeListInstances" />
	</xsl:template>
	
	<!-- 
		This template builds the instance that will be filled and send by the XForms. 
		@param element.type - the element type with the prefix of the namespace in which it is declared. 
		@param element.schema - The rootschema if leaved empty else the document in which the 
									   element is (must be) declared.
		@param element.prefix - Variable which contains the prefix for the namespace the elements belongs to.
	-->
	<xsl:template name="BuildMessageInstance">
		<xsl:param name="element.type"/>
		<xsl:param name="element.schema" />
		<xsl:param name="element.prefix" />
		
		<xsl:variable name="element.type.ns" 
			select="namespace-uri-for-prefix( substring-before( $element.type, ':' ), . )" />
		<!-- 
			When documentLocation is not set, it means that elementType is declared in the targetNamespace
			from the document.
		-->
		<xsl:for-each select="if( $element.schema = '') 
			then //xsd:complexType[@name = substring-after( $element.type, ':' ) ]
			else document( $element.schema )//xsd:complexType[@name = substring-after( $element.type, ':' ) ]">

			<xsl:for-each select="xsd:sequence/xsd:element">
				<xsl:choose>
					<xsl:when test="xsd:annotation/xsd:documentation/ccts:Acronym = 'BBIE'">
						<xsl:call-template name="DataType-instance-part">
							<xsl:with-param name="element.prefix" select="$element.prefix" />
							<xsl:with-param name="element.schema" select="$element.schema" />
						</xsl:call-template>
					</xsl:when>
					<xsl:otherwise>
						<xsl:variable name="element.ns" select="/xsd:schema/@targetNamespace"/>
						<xsl:variable name="element.child.type.ns" 
							select="namespace-uri-for-prefix( substring-before( @type, ':' ), . )"/>
						<xsl:variable name="element.child.type.prefix" select="substring-before( @type, ':' )" />
						
						<xsl:choose>
							<xsl:when test="namespace-uri-for-prefix( $element.prefix, . ) != $global.ns.target">
								<xsl:element name="{$element.prefix}:{@name}">
									<xsl:choose>
										<xsl:when test="$element.ns != $element.child.type.ns">
											<xsl:variable name="schema.next">
												<xsl:call-template name="GetDataTypeDocument">
													<xsl:with-param name="element.type" select="@type" />
													<xsl:with-param name="element.schema" 
														select="$element.schema" />
												</xsl:call-template>
											</xsl:variable>
											<xsl:call-template name="BuildMessageInstance">
												<xsl:with-param name="element.type" select="@type"/>
												<xsl:with-param name="element.prefix" 
													select="$element.child.type.prefix"/>
												<xsl:with-param name="element.schema" select="$schema.next" />
											</xsl:call-template>
										</xsl:when>
										<xsl:otherwise>
											<xsl:call-template name="BuildMessageInstance">
												<xsl:with-param name="element.type" select="@type"/>
												<xsl:with-param name="element.prefix" 
													select="$element.child.type.prefix"/>
												<xsl:with-param name="element.schema" 
													select="$element.schema" />
											</xsl:call-template>
										</xsl:otherwise>
									</xsl:choose>
								</xsl:element>
							</xsl:when>
							<xsl:otherwise>
								<!-- 
									If an element is defined in the rootschema it has to be in the namespace of the
									rootschema, otherwise it has to be in the name of the document in which it is
									declared.
								-->
								<xsl:element name="{@name}" namespace="{$global.ns.target}">
									<xsl:choose>
										<xsl:when test="$element.ns != $element.child.type.ns">
											<xsl:variable name="schema.next">
												<xsl:call-template name="GetDataTypeDocument">
													<xsl:with-param name="element.type" select="@type" />
													<xsl:with-param name="element.schema" 
														select="$element.schema" />
												</xsl:call-template>
											</xsl:variable>
											<xsl:call-template name="BuildMessageInstance">
												<xsl:with-param name="element.type" select="@type"/>
												<xsl:with-param name="element.prefix" 
													select="$element.child.type.prefix"/>
												<xsl:with-param name="element.schema" select="$schema.next" />
											</xsl:call-template>
										</xsl:when>
										<xsl:otherwise>
											<xsl:call-template name="BuildMessageInstance">
												<xsl:with-param name="element.type" select="@type"/>
												<xsl:with-param name="element.prefix" 
													select="$element.child.type.prefix"/>
											</xsl:call-template>
										</xsl:otherwise>
									</xsl:choose>
								</xsl:element>
							</xsl:otherwise>
						</xsl:choose>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:for-each>
		</xsl:for-each>
	</xsl:template>
	
	<xsl:template name="DataType-instance-part">
		<xsl:param name="element.prefix" />
		<xsl:param name="element.schema" />
		
		<xsl:variable name="type" select="substring-after( @type, ':' )" />
		
		<xsl:variable name="element.annotatedValue">
			<xsl:call-template name="GetAnnotatedValue">
				<xsl:with-param name="element.den" select="xsd:annotation/xsd:documentation/ccts:DictionaryEntryName" />
			</xsl:call-template>
		</xsl:variable>
		
		<!-- In the case of a code list it can be that the basetype is a contenttype. --> 
		
		<xsl:choose>
			<xsl:when test="contains( $global.datatypes.unqualified, $type )">
				<xsl:variable name="datatype.schema">
					<xsl:call-template name="GetDataTypeDocument">
						<xsl:with-param name="element.type" select="@type" />
						<xsl:with-param name="element.schema" select="$element.schema" />
					</xsl:call-template>
				</xsl:variable>
				<xsl:variable name="element.type.simple">
					<xsl:call-template name="BasedOnSimpleType">
						<xsl:with-param name="element.type" select="@type" />
						<xsl:with-param name="element.type.schema" select="$datatype.schema" />
					</xsl:call-template>
				</xsl:variable>
				<xsl:call-template name="UnqualifiedDataTypeInstancePart" >
					<xsl:with-param name="element.type" select="@type" />
					<xsl:with-param name="element.name" select="@name" />
					<xsl:with-param name="element.path" select="$element.prefix" />
					<xsl:with-param name="element.value" select="$element.annotatedValue" />
					<xsl:with-param name="element.simpleTypeBased" select="$element.type.simple" />
				</xsl:call-template>
			</xsl:when>
			<xsl:otherwise>
				<!-- First we have to look up on which unqualified datatype this type is based -->
				<xsl:variable name="datatype.schema">
					<xsl:call-template name="GetDataTypeDocument">
						<xsl:with-param name="element.type" select="@type" />
						<xsl:with-param name="element.schema" select="$element.schema" />
					</xsl:call-template>
				</xsl:variable>
				<xsl:variable name="element.type.unqualified">
					<xsl:call-template name="GetUnqualifiedDataType">
						<xsl:with-param name="element.type" select="@type" />
						<xsl:with-param name="element.type.schema" select="$datatype.schema" />
					</xsl:call-template>
				</xsl:variable>
				<xsl:variable name="element.type.simple">
					<xsl:call-template name="BasedOnSimpleType">
						<xsl:with-param name="element.type" select="@type" />
						<xsl:with-param name="element.type.schema" select="$datatype.schema" />
					</xsl:call-template>
				</xsl:variable>
				<xsl:call-template name="UnqualifiedDataTypeInstancePart">
					<xsl:with-param name="element.type" select="$element.type.unqualified" />
					<xsl:with-param name="element.name" select="@name" />
					<xsl:with-param name="element.path" select="$element.prefix" />
					<xsl:with-param name="element.value" select="$element.annotatedValue" />
					<xsl:with-param name="element.simpleTypeBased" select="$element.type.simple" />
				</xsl:call-template>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<xsl:template name="UnqualifiedDataTypeInstancePart">
		<xsl:param name="element.name" />
		<xsl:param name="element.type" />
		<xsl:param name="element.path" />
		<xsl:param name="element.value" required="yes" />
		<xsl:param name="element.simpleTypeBased" required="yes" />
		
		<xsl:if test="if( not( contains( $element.type, ':') ) )
			then error( QName( 'E', 'E' ), concat( 'instances.xsl 
				: UnqualifiedDataTypeInstancePart : element.type must contain a prefix 
					- value = ', $element.type, $element.name ) )
			else true()" />
		
		<xsl:variable name="type" select="substring-after( $element.type, ':' )" />
		
		<xsl:choose>
			<xsl:when test="$type = 'AmountType' ">
				<xsl:call-template name="AmountTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'BinaryObjectType'">
				<xsl:call-template name="BinaryObjectTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'CodeType' and $element.simpleTypeBased = false()">
				<xsl:call-template name="CodeTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
					<xsl:with-param name="value" select="$element.value" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'CodeType' and $element.simpleTypeBased = true()">
				<xsl:call-template name="CodeTypeSimpleInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
					<xsl:with-param name="value" select="$element.value" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'DateTimeType'">
				<xsl:call-template name="DateTimeTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'DateType'">
				<xsl:call-template name="DateTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'TimeType'">
				<xsl:call-template name="TimeTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'IDType' and $element.simpleTypeBased = false()">
				<xsl:call-template name="IDTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'IDType' and $element.simpleTypeBased = true()">
				<xsl:call-template name="IDTypeSimpleInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'IndicatorType'">
				<xsl:call-template name="IndicatorTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'MeasureType'">
				<xsl:call-template name="MeasureTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'NameType'">
				<xsl:call-template name="NameTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'QuantityType'">
				<xsl:call-template name="QuantityTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$type = 'TextType'">
				<xsl:call-template name="TextTypeInstancePart" >
					<xsl:with-param name="name" select="$element.name" />
					<xsl:with-param name="prefix" select="$element.path" />
				</xsl:call-template>
			</xsl:when>
			<xsl:otherwise>
				<xsl:element name="{$element.name}" namespace="{$global.ns.target}" >
					<xsl:attribute name="warning">unknown type: <xsl:value-of select="$element.type" /></xsl:attribute>
				</xsl:element>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<!-- 
		This template creates the instances that are needed  for the used datatypes.
	-->
	<xsl:template name="BuildCodeListInstances">
		<!-- $global.datatypes.used = declared in typelist.xsl -->
		<xsl:for-each select="$global.datatypes.used/types/codelistTypes/attribute">
			<xsl:element name="xf:instance">
				<xsl:attribute name="id" select="concat( 'instance.codes.', @name, '.', @type)" />
				<xsl:attribute name="src" select="@type.schema" />
			</xsl:element>
		</xsl:for-each>
	</xsl:template>
</xsl:stylesheet>